﻿using System;
using System.Collections.Generic;
using System.Linq;
using TimeMachine.Engine.Metrics;
using TimeMachine.Engine.Storing;
using TimeMachine.Engine.Vcs;

namespace TimeMachine.Engine.Analytics.Impl
{
	// Значение в точке t — это сумма значений из промежутка (t-period; t]
	public class Averager : IPlotDataProvider
	{
		private readonly IMetric[] metrics;
		private readonly IPlotSettings plotSettings;
		private readonly IMetricsStorage metricsValues;
		private readonly ICommitsInfoProvider commits;

		public Averager(IMetricsStorage metricsValues, ICommitsInfoProvider commits,
			IPlotSettings plotSettings, IMetric[] metrics)
		{
			this.metricsValues = metricsValues;
			this.commits = commits;
			this.plotSettings = plotSettings;
			this.metrics = metrics;
		}

		public PlotData Get(int timePointsCount)
		{
			string metricName = plotSettings.MetricName;
			IMetric metric = metrics.Single(m => m.Desc.MetricId == metricName);
			string author = metric.Desc.ShowPersonalMetrics ? plotSettings.Author : null;
			IEnumerable<CommitMetric> commitMetrics = 
				commits.GetCommitMetrics(metricName, metricsValues)
				.Where(c => c.Commit.Date >= plotSettings.FromDate && c.Commit.Date <= plotSettings.TillDate);
			var res = new List<PlotPoints>();
			if(!commitMetrics.Any()) return new PlotData(new PlotPoints[0], new string[0]);
			TimeSpan timeframe = TimeSpan.FromDays((commitMetrics.Last().Commit.Date - commitMetrics.First().Commit.Date).TotalDays / (timePointsCount - 1));
			string[] names = plotSettings.Author == null ? new[] {"all"} : new[] {plotSettings.Author};

			DateTime currentFrameStart = commitMetrics.First().Commit.Date;
			IAggregator total = metric.CreateAggregator();
			IAggregator byAuthor = metric.CreateAggregator();
			foreach (CommitMetric commit in commitMetrics)
			{
				DateTime time = currentFrameStart + timeframe.Div(2);
				while(commit.Commit.Date > currentFrameStart + timeframe)
				{
					var values =
						author == null
							? new[] { total.GetResult(timeframe.TotalDays) }
							: new[] { byAuthor.GetResult(timeframe.TotalDays) };
					res.Add(new PlotPoints(time, values));
					total.StartNewPeriod();
					byAuthor.StartNewPeriod();
					currentFrameStart += timeframe;
				}
				double value = commit.Metric.Value;
				total.Aggregate(value);
				if(commit.Commit.Author == plotSettings.Author) byAuthor.Aggregate(value);
			}
			if (res.Count < timePointsCount)
			{
					var values =
						author == null
							? new[] { total.GetResult(timeframe.TotalDays) }
							: new[] { byAuthor.GetResult(timeframe.TotalDays) };
					res.Add(new PlotPoints(commitMetrics.Last().Commit.Date, values));
			}
			return new PlotData(res.ToArray(), names);
		}
	}
}